///
/// @file CastInstruction.cpp
/// @brief 类型转换指令
/// @version 1.0
/// @date 2024-09-29
///
/// @copyright Copyright (c) 2024
///
/// @par 修改日志:
/// <table>
/// <tr><th>Date       <th>Version <th>Author  <th>Description
/// <tr><td>2024-09-29 <td>1.0     <td>zenglj  <td>新建
/// </table>
///

#include "CastInstruction.h"
#include "Function.h"
#include "RegVariable.h"
#include <GlobalVariable.h>
#include <LocalVariable.h>

/// @brief 构造函数
/// @param _func 所属函数
/// @param _srcVal 源操作数
/// @param _type 目标类型
CastInstruction::CastInstruction(Function * _func, Value * _srcVal, Type * _type)
    : Instruction(_func, IRInstOperator::IRINST_OP_CAST, _type)
{
    addOperand(_srcVal);
}

/// @brief 转换成字符串
/// @param str 转换后的字符串
void CastInstruction::toString(std::string & str)
{
    Value * srcVal = getOperand(0);
    std::string srcName;

    // 对内存型 Value 先 load
    if (dynamic_cast<LocalVariable *>(srcVal) != nullptr || dynamic_cast<GlobalVariable *>(srcVal) != nullptr) {
        RegVariable * tmp = func->newTempVariable(srcVal->getType());
        srcName = tmp->getIRName();
        str = srcName + " = load " + srcVal->getType()->toString() + ", " + srcVal->getType()->toString() + "* " +
              srcVal->getIRName() + "\n\t";
    } else {
        srcName = srcVal->getIRName();
        str.clear();
    }

    Type * srcType = srcVal->getType();
    Type * destType = getType();

    // float -> int : fptosi
    if (srcType->isFloatType() && destType->isIntegerType()) {
        str += getIRName() + " = fptosi " + srcType->toString() + " " + srcName + " to " + destType->toString();
    }
    // int -> float : sitofp
    else if (srcType->isIntegerType() && destType->isFloatType()) {
        str += getIRName() + " = sitofp " + srcType->toString() + " " + srcName + " to " + destType->toString();
    }
    // i32 -> i1 : bool 化
    else if (srcType->isInt32Type() && destType->isInt1Byte()) {
        str += getIRName() + " = icmp ne " + srcType->toString() + " " + srcName + ", 0";
    }
    // i1 -> i32 : zero extend
    else if (srcType->isInt1Byte() && destType->isInt32Type()) {
        str += getIRName() + " = zext " + srcType->toString() + " " + srcName + " to " + destType->toString();
    }
    // float -> i1 : fcmp one
    else if (srcType->isFloatType() && destType->isInt1Byte()) {
        str += getIRName() + " = fcmp one " + srcType->toString() + " " + srcName + ", 0.0";
    }
    // i1 -> float : uitofp
    else if (srcType->isInt1Byte() && destType->isFloatType()) {
        str += getIRName() + " = uitofp " + srcType->toString() + " " + srcName + " to " + destType->toString();
    }
    // 扩宽
    else if (srcType->toString() != destType->toString() && srcType->getSize() < destType->getSize()) {
        str += getIRName() + " = zext " + srcType->toString() + " " + srcName + " to " + destType->toString();
    }
    // 缩窄
    else if (srcType->toString() != destType->toString() && srcType->getSize() > destType->getSize()) {
        str += getIRName() + " = trunc " + srcType->toString() + " " + srcName + " to " + destType->toString();
    }
    // 同宽按 bitcast
    else {
        str += getIRName() + " = bitcast " + srcType->toString() + " " + srcName + " to " + destType->toString();
    }
}